/***************************************************************************
 *   Ants - library                                                        *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/


#ifndef ANTS_UDP_WATCHER_HPP
#define ANTS_UDP_WATCHER_HPP

#include    <list>
#include    <map>

#include    "ev/ev++.h"
#include    "zsocket/udper.hpp"

#include    "help/string.hpp"
#include    "common/packet.hpp"
#include    "common/exception.hpp"

namespace   ants
{

struct  UdpWatcher  :   public  ev::io
{
public  :
    UdpWatcher(int port) : m_iPort(port), m_pUdper(NULL)
    {
        m_pUdper = new zsocket::Udper();
        m_pUdper->open(port);
    }
    
    ~UdpWatcher()
    {
        if (NULL != m_pUdper) {
            m_pUdper->close();
            delete m_pUdper;
        }
    }
    
    int     descriptor(void)
    {
        if ( NULL == m_pUdper ) {
            return  0;
        }
        
        return  m_pUdper->descriptor();
    }

public  :

    void    engageSynToSend(const zsocket::Address& address, ant::Packet::serial_type serialFor) throw (ant::Exception);
    void    cancelSynToSend(const zsocket::Address& address, ant::Packet::serial_type serialFor) throw (ant::Exception);
    
    void    flush(void) throw (ant::Exception);

private :
    void    flushSynPackets(void) throw (ant::Exception);
    void    flushAckPackets(void) throw (ant::Exception);
    void    flushDataPackets(void) throw (ant::Exception);
    
    void    getSynPacket(ant::Packet*& pPacket) throw (ant::Exception);
    void    releaseSynPacket(ant::Packet*& pPacket) throw (ant::Exception);
    
public  :
    
    void    send(const zsocket::Address& address, std::string& strPacket) throw (ant::Exception);
    void    send(const zsocket::Address& address, const void* pvData, unsigned iDataSize) throw (ant::Exception)
    {
        try {
            m_pUdper->sendto(address, pvData, iDataSize);
        }
        catch (zsocket::Exception& ex) {
            throw ant::Exception(help::String::format("UdpWatcher::send zsocket::Exception : [%d] %s", ex.getCode(), ex.what()), ant::ANTC_EUNKNOWN);
        }
        catch (std::exception& ex) {
            throw ant::Exception(help::String::format("UdpWatcher::send std::exception : %s", ex.what()), ant::ANTC_EUNKNOWN);
        }
    }
    
    void    recv(zsocket::Address& address, std::string& strPacket) throw (ant::Exception)
    {
        try {
            m_pUdper->recvfrom(address, strPacket);
        }
        catch (zsocket::Exception& ex) {
            throw ant::Exception(help::String::format("UdpWatcher::recv zsocket::Exception : [%d] %s", ex.getCode(), ex.what()), ant::ANTC_EUNKNOWN);
        }
        catch (std::exception& ex) {
            throw ant::Exception(help::String::format("UdpWatcher::recv std::exception : %s", ex.what()), ant::ANTC_EUNKNOWN);
        }
    }
    
private :
    int     m_iPort;
    zsocket::Udper*  m_pUdper;
    
    typedef std::list< ant::Packet* >     queue_syn_packet_type;
    typedef std::map< zsocket::Address, queue_syn_packet_type >     room_syn_packet_type;
    
    room_syn_packet_type       m_room_syn_packet_sending;
    
};  // UdpWatcher

}   // namespace ants

#endif  
